import * as cc from "cc";
import BaseComponent from "../components/BaseComponent";
import { ViewCtrlBase } from './ViewCtrlBase';
import { ViewEventDefine } from "./ViewEventDefine";
import { TweenEasing } from "../utils/AnimationUtils";

/**UI状态 */
export enum ViewLiftCycle {
    INIT,
    OPEN,
    SHOW,
    ONSTART,
    UPDATE,
    HIDE,
    CLOSE,
    DESTORY,
}

export enum ViewAnimType {
    NONE = 0,
    SCALE,
    FADEIN,
    MOVE_TO_BOTTOM,
    MOVE_TO_TOP,
    MOVE_TO_RIGHT,
    /**弹出Tips类型动画 */
    TIPS,
}
const { ccclass, property, menu } = cc._decorator;
@ccclass
export class ViewBase extends BaseComponent {

    @property({ displayName: "是否添加屏蔽层" })
    isBlock: boolean = true;
    @property({ displayName: "是否点击空白关闭", visible() { return this.isBlock === true } })
    isCloseBg: boolean = true;
    @property({ type: cc.Enum(ViewAnimType), displayName: "打开动画类型" })
    viewAnimType: ViewAnimType = ViewAnimType.NONE;

    @property({ type: cc.Node, tooltip: "背景层,全屏缩放,防止点击事件穿透,也可用于点击任意位置关闭的弹窗", visible() { return this.isBlock === true } })
    background: cc.Node = null;

    @property({ type: cc.UITransform, tooltip: "UI通用开启和关闭动画使用的内容" })
    contentView: cc.UITransform = null;
    @property({ displayName: "是否使用关闭按钮" })
    isBtnClose: boolean = false;
    @property({ type: cc.Node, tooltip: "关闭按钮", visible() { return this.isBtnClose === true } })
    btnClose: cc.Node = null;

    protected static prefabUrl: string = null;
    public static className: string = null
    //代理控制器，所有复杂逻辑均由代理控制器完成
    protected vc: ViewCtrlBase = null
    private _startCallback: () => void = null;
    private _closeCallback: () => void;

    /**UI运行生命周期 */
    private _lifeCycle: ViewLiftCycle;
    /**关闭状态,true:直接destory,false:active false  */
    private _isDestory: boolean;

    protected rightX: number = 0;
    protected topY: number = 0;
    protected contentViewPos: cc.Vec3 = null;

    public static getUrl() {
        return this.prefabUrl;
    }

    public setCtrl(ctrl: ViewCtrlBase) {
        this.vc = ctrl;
    }

    public setStartCallback(startCallback: () => void) {
        this._startCallback = startCallback;
    }

    onLoad() {
        super.onLoad();
    }

    start() {
        super.start();
        let preloadList = this.getPreloadResPath();
        if (preloadList && preloadList.length > 0) {
            this.preloadRes().then(() => {
                this.changeLifeCycle(ViewLiftCycle.INIT);
                this._startCallback && this._startCallback();
            })
        } else {
            this.changeLifeCycle(ViewLiftCycle.INIT);
            this._startCallback && this._startCallback();
        }
    }

    update(dt) {
        if (this._lifeCycle != ViewLiftCycle.UPDATE) {
            return;
        }
        this.onUpdate(dt);
    }

    onDestroy() {
        // Loger.logView(`=====>>>>${this.node.name}==>>onDestroy`);
        this.changeLifeCycle(ViewLiftCycle.DESTORY);
        super.onDestroy();
    }

    changeLifeCycle(lifeCycle: ViewLiftCycle) {
        if (this._lifeCycle == lifeCycle) {
            return;
        }
        this._lifeCycle = lifeCycle;
        switch (lifeCycle) {
            case ViewLiftCycle.INIT:
                this._changeInit();
                break;
            case ViewLiftCycle.OPEN:
                this._changeOpen();
                break;
            case ViewLiftCycle.SHOW:
                this._changeShow();
                break;
            case ViewLiftCycle.ONSTART:
                this._changeStart();
                break;
            case ViewLiftCycle.HIDE:
                this._changeHide();
                break;
            case ViewLiftCycle.CLOSE:
                this._changeClose();
                break;
            default:
                break;
        }
    }
    private _changeInit() {
        this.onInit();
        this.changeLifeCycle(ViewLiftCycle.OPEN);
    }
    private _changeOpen() {
        this.onOpen();
        this.changeLifeCycle(ViewLiftCycle.SHOW);
    }
    private _changeShow() {
        this.onShow(() => { this.changeLifeCycle(ViewLiftCycle.ONSTART); });
    }

    private _changeStart() {
        this.onStart();
        this.changeLifeCycle(ViewLiftCycle.UPDATE);
    }

    private _changeHide() {
        this.onHide(() => {
            this.changeLifeCycle(ViewLiftCycle.CLOSE);
        })
    }

    private _changeClose() {
        this.onClose();
    }
    public checkCanOpen(): boolean {
        if (this._lifeCycle == ViewLiftCycle.HIDE) {
            return false;
        }
        return true;
    }

    public checkCanClose(): boolean {
        if (this._lifeCycle != ViewLiftCycle.ONSTART && this._lifeCycle != ViewLiftCycle.UPDATE) {
            return false;
        }
        return true;
    }
    /**通用关闭按钮响应事件,子类可重写 */
    protected onBtnClose_click(ev: cc.EventTouch) {
        this.close()
    }

    //生命周期：onInit(加载时只调一次)==>onOpen(每次showui时)==>onShow()==>onStart()==>onHide()==>onClose()
    /**只会在首次加载时调用一次，可以用于获取节点，绑定事件 */
    protected onInit() {
        // Loger.logView(`=====>>>>${this.node.name}==>>onInit`);        
        this.rightX = this.parentUiTrans.width * 0.5;
        this.topY = this.parentUiTrans.height * 0.5;
        if (this.background) {
            if (this.isCloseBg) {
                this.setClickListenerNoAnim(this.background, this.onBtnClose_click, this);
            }
            if (this.isBlock) {
                //防止事件点击穿透，需要加一个bg层，background的大小决定屏蔽穿透的区域
                this.background.getComponent(cc.BlockInputEvents) || this.background.addComponent(cc.BlockInputEvents);
            }
        }
        if (this.contentView) {
            this.contentViewPos = cc.v3(this.contentView.node.position.x, this.contentView.node.position.y, this.contentView.node.position.z);
            // this.contentView.node.active = false;
            this.contentView.getComponent(cc.BlockInputEvents) || this.contentView.addComponent(cc.BlockInputEvents);
        }

        if (this.btnClose) {
            this.setClickListener(this.btnClose, this.onBtnClose_click, this);
        }
    }
    /**每次打开UI前，onStart前,每次呼出前赋值传参的时候用 */
    protected onOpen() {
        // Loger.logView(`=====>>>>${this.node.name}==>>onOpen`);
        this.node.active = true;
        this.vc.onOpen();
    }
    //有的层显示/隐藏需要一定的动画过程.需要等动画结束后才能做一些其他事情,如隐藏节点等.
    protected onShow(callback: () => void) {
        // Loger.log(`=====>>>>${this.node.name}==>>onShow`);
        if (!this.contentView) {
            callback();
            return
        }

        cc.Tween.stopAllByTarget(this.contentView.node)
        const scaleTween = () => {
            this.contentView.node.active = true;
            this.contentView.node.scale = cc.v3(0.8, 0.8, 1);
            cc.tween(this.contentView.node)
                .to(0.2, { scale: cc.v3(1, 1, 1) }, { easing: TweenEasing.backOut })
                .call(() => {
                    callback();
                })
                .start();
        }

        const fadeInTween = () => {
            const opacityCom = this.contentView.node.getComponent(cc.UIOpacity) || this.contentView.node.addComponent(cc.UIOpacity);
            opacityCom.opacity = 0;
            this.contentView.node.active = true;
            cc.tween(opacityCom)
                .to(0.2, { opacity: 255 }, { easing: TweenEasing.smooth })
                .call(() => {
                    callback();
                })
                .start();
        }

        const moveTween = (x: number, y: number, z?: number) => {
            this.contentView.node.setPosition(x, y, z);
            this.contentView.node.active = true;
            cc.tween(this.contentView.node)
                .to(0.2, { position: this.contentViewPos }, { easing: TweenEasing.smooth })
                .call(() => {
                    callback();
                })
                .start();
        }

        const tipsTween = () => {
            const opacityCom = this.contentView.node.getComponent(cc.UIOpacity) || this.contentView.node.addComponent(cc.UIOpacity);
            opacityCom.opacity = 0;
            this.contentView.node.active = true;
            cc.tween(opacityCom)
                .to(0.2, { opacity: 255 }, { easing: TweenEasing.smooth })
                .call(() => {
                    callback();
                })
                .start();
        }

        switch (this.viewAnimType) {
            case ViewAnimType.SCALE:
                scaleTween();
                break;
            case ViewAnimType.MOVE_TO_BOTTOM:
                moveTween(this.contentViewPos.x, this.contentViewPos.y - this.contentView.height, this.contentViewPos.z);
                break;
            case ViewAnimType.MOVE_TO_TOP:
                moveTween(this.contentViewPos.x, this.contentViewPos.y + this.contentView.height, this.contentViewPos.z);
                break;
            case ViewAnimType.MOVE_TO_RIGHT:
                moveTween(this.contentViewPos.x + this.contentView.width, this.contentViewPos.y, this.contentViewPos.z);
                break;
            case ViewAnimType.FADEIN:
                fadeInTween();
                break;
            case ViewAnimType.TIPS:
                tipsTween();
                break;
            case ViewAnimType.NONE:
                this.contentView.node.active = true;
                callback();
                break;
            default:
                break;
        }

    }

    /**开始动画播完后 onShow后*/
    protected onStart() {
        // Loger.logView(`=====>>>>${this.node.name}==>>onStart`);

    }

    protected onUpdate(dt) {
    }

    /**播放结束动画 */
    protected onHide(callback: () => void) {
        // Loger.logView(`=====>>>>${this.node.name}==>>onHide`);
        if (!this.contentView) {
            callback();
        } else {
            cc.Tween.stopAllByTarget(this.contentView.node)
            const scaleTween = () => {
                cc.tween(this.contentView.node)
                    .to(0.2, { scale: cc.v3(0.8, 0.8, 0.8) }, { easing: TweenEasing.backOut })
                    .call(() => {
                        callback();
                    })
                    .start();
            }

            const fadeOutTween = () => {
                const opacityCom = this.contentView.node.getComponent(cc.UIOpacity) || this.contentView.node.addComponent(cc.UIOpacity);
                cc.tween(opacityCom)
                    .to(0.2, { opacity: 0 }, { easing: TweenEasing.smooth })
                    .call(() => {
                        callback();
                    })
                    .start();
            }

            const moveTween = (x: number, y: number, z?: number) => {
                cc.tween(this.contentView.node)
                    .to(0.2, { position: cc.v3(x, y, z) }, { easing: TweenEasing.smooth })
                    .call(() => {
                        callback();
                    })
                    .start();
            }

            const tipsTween = () => {
                const opacityCom = this.contentView.node.getComponent(cc.UIOpacity) || this.contentView.node.addComponent(cc.UIOpacity);
                const node = this.contentView.node;
                const moveTime = 0.5;
                cc.tween(node)
                    .to(moveTime, { position: cc.v3(node.position.x, node.position.y + 50, node.position.z) }, { easing: TweenEasing.smooth })
                    .start();
                cc.tween(opacityCom)
                    .delay(moveTime)
                    .to(0.2, { opacity: 0 }, { easing: TweenEasing.smooth })
                    .call(() => {
                        callback();
                    })
                    .start();
            }

            switch (this.viewAnimType) {
                case ViewAnimType.SCALE:
                    // scaleTween();
                    callback();
                    break;
                case ViewAnimType.MOVE_TO_BOTTOM:
                    moveTween(this.contentViewPos.x, this.contentViewPos.y - this.contentView.height, this.contentViewPos.z);
                    break;
                case ViewAnimType.MOVE_TO_TOP:
                    moveTween(this.contentViewPos.x, this.contentViewPos.y + this.contentView.height, this.contentViewPos.z);
                    break;
                case ViewAnimType.MOVE_TO_RIGHT:
                    moveTween(this.contentViewPos.x + this.contentView.width, this.contentViewPos.y, this.contentViewPos.z);
                    break;
                case ViewAnimType.FADEIN:
                    fadeOutTween();
                    break;
                case ViewAnimType.TIPS:
                    tipsTween();
                    break;
                case ViewAnimType.NONE:
                    callback();
                    break;
                default:
                    callback();
                    break;
            }

        }
    }
    /**关闭动画结束后 */
    protected onClose() {
        // Loger.logView(`=====>>>>${this.node.name}==>>onClose`);
        this._closeCallback && this._closeCallback();
        this._closeCallback = null;

        if (this._isDestory) {
            this.node.destroy();
        } else {
            this.node.active = false;
        }

        if (this.vc) {
            ViewEventDefine.ON_VIEW_CLOSE.emit(this.vc.viewName);
            this.vc.onClose();
            this.vc = null;
        }
    }

    public setDestory() {
        this._isDestory = true;
        this.onClose();
    }

    /**给ui管理器调度用的,不要手动调用 */
    __beginClose(closeCallback: () => void) {
        this._closeCallback = closeCallback;
        this._isDestory = false;
        this.changeLifeCycle(ViewLiftCycle.HIDE);
    }

    /**给ui管理器调度用的,不要手动调用 */
    __beginRemove(closeCallback: () => void) {
        this._closeCallback = closeCallback;
        this._isDestory = true;
        this.changeLifeCycle(ViewLiftCycle.HIDE);
    }

    /**
     * @desc 关闭UI
     * @param isRemove 是否使用删除
     * 特殊情况,需要频繁打开的UI,可以传入false,使用隐藏UI的方式关闭
     */
    public close(isRemove: boolean = true) {
        this.vc && this.vc.close(isRemove);
    }
}